package me.yricky.chart.content.coordinate

import android.view.MotionEvent
import androidx.compose.foundation.Canvas
import androidx.compose.runtime.*
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.input.pointer.pointerInteropFilter
import kotlinx.coroutines.launch
import me.yricky.chart.base.CoordinateDatasets
import me.yricky.chart.base.DataRange
import me.yricky.chart.base.Dataset
import me.yricky.chart.base.relativeLocationIn
import kotlin.math.abs

@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun <T> LineChart(
    modifier: Modifier = Modifier,
    dataSets:CoordinateDatasets<T>,
    chartTheme: ChartTheme = chartTheme{},
    chartModifier: ChartModifier = chartModifier{},
    onSelect:((Dataset<T>,T)->Unit)? = null,
){
    val yRange:DataRange = dataSets.yRange.let { chartModifier.yRangeTrans(it) }
    val xRange:DataRange = dataSets.xRange.let { chartModifier.xRangeTrans(it) }

    val dataLocation:(Size, T)->Offset = { size:Size,data:T ->
        val relX = dataSets.dataXValue(data).relativeLocationIn(xRange)
        val relY = dataSets.dataYValue(data).relativeLocationIn(yRange)
        val x = relX * size.width
        val y = (1 - relY) * size.height
        Offset(x.toFloat(),y.toFloat())
    }
    var size0 by remember {
        mutableStateOf(Size.Zero)
    }
    var d:Pair<Dataset<T>,T>? by remember {
        mutableStateOf(null)
    }
    val scope = rememberCoroutineScope()
    Canvas(modifier.pointerInteropFilter { event ->
        when(event.action){
            MotionEvent.ACTION_MOVE,MotionEvent.ACTION_DOWN -> {
                d = dataSets.datasets.mapNotNull { ds ->
                    ds.data.findLast {
                        dataLocation(size0, it).x < event.x
                    }?.let { Pair(ds, it) }
                }.minByOrNull {
                    abs(dataLocation(size0, it.second).y - event.y)
                }
                d?.let{
                    scope.launch {
                        onSelect?.invoke(it.first,it.second)
                    }
                }
            }
            else ->{}
        }
        true
    }){
        size0 = size
        dataSets.datasets.forEach {
            val sortedList = it.data
            if(sortedList.size > 1){
                var xy0 = dataLocation(size,sortedList.first())
                sortedList.forEach {
                    val xy = dataLocation(size,it)
                    drawLine(chartTheme.lineColor,xy0,xy,2f)
                    xy0 = xy
                }
                if(onSelect != null){
                    d?.let{
                        val xy = dataLocation(size,it.second)
                        drawLine(chartTheme.cursorColor,Offset(xy.x,0f),Offset(xy.x,size.height),2f)
                        drawLine(chartTheme.cursorColor,Offset(0f,xy.y),Offset(size.width,xy.y),2f)
                    }
                }
            }
        }
    }
}